package cn.t.dynamic.switcher.router;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;

/**
 * 动态数据源<br/>
 * AbstractRoutingDataSource中有一个TargetDataSources的HashMap,这个Map维护了数据源key-数据源对象的键值对
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);

    private DataSource defaultTargetDataSource;

    @Override
    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
        logger.info("default dataSource has been setup...");
        this.defaultTargetDataSource = (DataSource) defaultTargetDataSource;
    }

    /**
     * 确定当前需要获取的数据源key-父类中根据key获取对应的数据源
     * @return 数据源的key
     */
    @Override
    protected String determineCurrentLookupKey() {
        String key = DynamicDataSourceContextHolder.current();
        logger.info("Current DataSource Is {}", key);
        return key;
    }

    /**
     * 重写查找数据源的方法-一般重写determineCurrentLookupKey已经足够满足业务需求了
     * @return 确定的数据源
     */
    @Override
    protected DataSource determineTargetDataSource() {
        // 由于重写了determineTargetDataSource方法,所以此处determineCurrentLookupKey的作用可有可无
        String lookupKey = this.determineCurrentLookupKey();

        if (lookupKey == null || DynamicDataSourceContextHolder.getDataSource(lookupKey) == null) {
            logger.info("use the default dataSource...");
            return this.defaultTargetDataSource;
        }
        var ds = DynamicDataSourceContextHolder.getDataSource(lookupKey);

        // ThreadLocal的key为弱引用,可能已经被GC回收了
        if (ds == null) {
            // 清除缓存
            logger.warn("dataSource key has been garbage collected... current dataSource has been convert to the default dataSource");
            DynamicDataSourceContextHolder.reset();
            return this.defaultTargetDataSource;
        }
        return ds;
    }

    /**
     * 重写afterPropertiesSet,让数据源可以在容器初始化后再设置
     */
    @Override
    public void afterPropertiesSet() {
      logger.info("AbstractRoutingDataSource has been override...default setup will not be executed...");
    }
}
